package com.evangelion.core.daoImpl;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

public abstract class AbstractDAO<T> {

    @PersistenceContext
    protected EntityManager em;

    private static final Logger log = Logger.getLogger(AbstractDAO.class.getName());

    @Transactional(propagation = Propagation.REQUIRED)
    public void save(T entity) {
        em.merge(entity);
        em.flush();
    }

    @Transactional(propagation = Propagation.REQUIRED)
    protected void delete(T entity) {
        em.remove(entity);
        em.flush();
    }

    protected T find(Class<T> clazz, Object id) {
        return em.find(clazz, id);
    }

    public List<T> findListByParam(Class<T> clazz, String param, String value) {
        Query q = em.createQuery(String.format("SELECT e FROM %s e where e.%s=:valor", clazz.getSimpleName(), param));
        q.setParameter("valor", "%" + value + "%");
        return q.getResultList();
    }

    public T findObjByParam(Class<T> clazz, String param, String value) {
        Query q = em.createQuery("SELECT x FROM " + clazz.getSimpleName() + " x where x." + param + "=:valor");
        q.setParameter("valor", value);
        return getSingleResult(q);
    }

    public int countPage(Class<T> clazz, String value) {
        Query q = em.createQuery(String.format("SELECT COUNT(a.id) FROM %s a", clazz.getSimpleName()));
        return (Integer) q.getSingleResult();
    }

    public List<T> listActive(Class<T> clazz) {
        Query q = em.createQuery(String.format("SELECT x FROM %s x", clazz.getSimpleName()));
        return q.getResultList();
    }

    public List<T> ListAll(Class<T> clazz) {
        return listActive(clazz);
    }

    public void applyParams(Query q, Map<String, Object> pMap) {
        for (String key : pMap.keySet()) {
            q.setParameter(key, pMap.get(key));
        }
    }

    private T getSingleResult(Query q) {
        try {
            return (T) q.getSingleResult();
        } catch (NoResultException e) {
            log.warning(String.format("No results found for query %s", q.toString()));
            return null;
        }
    }
}
